#ifndef __MY_UTIL__ //如果 __MY_UTIL__被定义了就不会加载这个库了
#define __MY_UTIL__

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <mutex>
#include <sys/stat.h>
#include <experimental/filesystem>
#include <jsoncpp/json/json.h>
#include "bundle.h"

namespace cloud
{
    namespace fs = std::experimental::filesystem;
    class FileUtil
    {
    private:
        std::string _filename;

    public:
        FileUtil(std::string filename) : _filename(filename) {}

        size_t FileSize() // 获取文件大小
        {
            struct stat st;
            int ret = stat(_filename.c_str(), &st);
            if (ret < 0)
            {
                std::cout << "stat error->FileSize" << std::endl;
                return -1;
            }
            return st.st_size;
        }
        time_t LassMTime() // 获取文件最后一次修改时间
        {
            struct stat st;
            int ret = stat(_filename.c_str(), &st);
            if (ret < 0)
            {
                std::cout << "stat error->LassMTime" << std::endl;
                return -1;
            }
            return st.st_mtim.tv_sec;
        }
        time_t LassATime() // 获取文件最后一次访问时间
        {
            struct stat st;
            int ret = stat(_filename.c_str(), &st);
            if (ret < 0)
            {
                std::cout << "stat error->LassATime" << std::endl;
                return -1;
            }
            return st.st_atim.tv_sec;
        }
        std::string FileName() // 获取文件的名称
        {                      //./abc/test.c
            auto pos = _filename.find_last_of("/");
            if (pos == std::string::npos)
            {
                return _filename;
            }
            return _filename.substr(pos + 1);
        }
        bool GetPosLen(std::string *body, size_t pos, size_t len) // 获取指定文件指定位置指定长度的数据
        {
            size_t size = this->FileSize();
            if (pos + len > size)
            {
                std::cout << "get data overflow" << std::endl;
                return false;
            }
            std::ifstream ifs;
            ifs.open(_filename, std::ios::binary);
            if (ifs.is_open() == false) // 检测流的状态
            {
                std::cout << "read open error1" << std::endl;
                return false;
            }
            ifs.seekg(pos);
            body->resize(len);
            ifs.read(&(*body)[0], len); // 存在&与*优先级问题
            if (ifs.good() == false)    // 检测流的状态
            {
                std::cout << "read open error2" << std::endl;
                ifs.close();
                return false;
            }
            ifs.close();
            return true;
        }
        bool GetContent(std::string *body) // 获取指定文件的数据
        {
            return GetPosLen(body, 0, this->FileSize());
        }
        bool SetContent(const std::string &body) // 对文件写入数据body
        {
            std::ofstream ofs;
            ofs.open(_filename, std::ios::binary);
            if (ofs.is_open() == false) // 检测流的状态
            {
                std::cout << "write open error1" << std::endl;
                return false;
            }
            ofs.write(&body[0], body.size());
            if (ofs.good() == false) // 检测流的状态
            {
                std::cout << "write open error2" << std::endl;
                ofs.close();
                return false;
            }
            ofs.close();
            return true;
        }
        bool Compress(const std::string &packname) // 压缩文件
        {
            // 1.获取原始文件数据
            std::string body;
            if (this->GetContent(&body) == false)
            {
                std::cout << "Compress getcontent error" << std::endl;
                return false;
            }
            // 2.压缩
            std::string packed = bundle::pack(bundle::LZIP, body);
            // 3.将压缩数据写入指定文件中
            // _filename = packname;
            FileUtil fu(packname);
            if (fu.SetContent(packed) == false)
            {
                std::cout << "Compress setContent error" << std::endl;
                return false;
            }
            return true;
        }
        bool UnCompress(const std::string &filename) // 解压文件
        {
            // 1.获取原始文件的数据
            std::string body;
            if (this->GetContent(&body) == false)
            {
                std::cout << "UnCompress getcontent error" << std::endl;
                return false;
            }
            // 2.解压缩
            std::string unpacked = bundle::unpack(body);
            // 3.将解压缩的数据写入指定文件
            // _filename = filename;
            FileUtil fu(filename);
            if (fu.SetContent(unpacked) == false)
            {
                std::cout << "UnCompress setContent error" << std::endl;
                return false;
            }
            return true;
        }
        bool Remove()
        {
            if(Exists() == false) return false;
            remove(_filename.c_str());
            return true;
        }
        bool Exists() // 判断文件是否存在
        {
            return fs::exists(_filename);
        }
        bool CreateDirectory() // 创建目录
        {
            if (this->Exists())
                return true;
            return fs::create_directories(_filename);
        }
        bool ScanDirectory(std::vector<std::string> *arry) // 浏览获取目录下所有文件路径名
        {
            for (auto &p : fs::directory_iterator(_filename))
            {
                if (fs::is_directory(p) == true)
                    continue;
                arry->push_back(fs::path(p).relative_path().string());
            }
            return true;
        }
    };
    class JsonUtil
    {
    public:
        static bool Serialize(const Json::Value &root, std::string *str) // 序列化
        {
            Json::StreamWriterBuilder swb;                                 // 用于创建StreamWriter类
            std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter()); // 智能指针管理StreamWriter对象

            std::stringstream ss;          // ss一种文件流，存储各种数据
            if (sw->write(root, &ss) != 0) // 将root对象中的数据写入ss中
            {
                std::cout << "Serialize write error" << std::endl;
                return false;
            }
            *str = ss.str();
            return true;
        }

        static bool UnSerialize(const std::string &str, Json::Value *root) // 反序列化
        {
            Json::CharReaderBuilder crb;
            std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
            std::string err;
            bool ret = cr->parse(str.c_str(), str.c_str() + str.size(), root, &err);
            if (ret == false)
            {
                std::cout << "UnSerialize parse error:" << err << std::endl;
                return false;
            }
            return true;
        }
    };

   
} // namespace cloud

#endif